package com.dmgis.qxfw.dataservice.businessservice.common.util;

import com.alibaba.fastjson.JSON;
import org.apache.commons.codec.binary.Hex;
import org.apache.commons.collections.comparators.ComparableComparator;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.StringUtils;

import java.io.UnsupportedEncodingException;
import java.lang.reflect.Method;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.*;

/**
 * @Author: tangsiwei
 * @Date: 2020/10/14 15:53
 */
public class SignatureUtil {
    private static final Logger log = LoggerFactory.getLogger(SignatureUtil.class);
    public static final Comparator CASE_INSENSITIVE;
    public static final Comparator CASE_SENSITIVE;

    protected SignatureUtil() {
    }

    public static String getMD5Sign(Object o, String apiKey) {
        return getSign(o, apiKey, "MD5");
    }

    public static String getMD5Sign(Object o, String apiKey, Comparator comparator) {
        return getSign(o, apiKey, "MD5", comparator);
    }

    public static String getSign(Object dataInfo, String apiKey, String algorithm) {
        return null != dataInfo && dataInfo instanceof Map ? getSignFromMap((Map)dataInfo, apiKey, algorithm) : getSignFromObject(dataInfo, apiKey, algorithm);
    }

    public static String getSign(Object dataInfo, String apiKey, String algorithm, Comparator comparator) {
        return null != dataInfo && dataInfo instanceof Map ? getSignFromMap((Map)dataInfo, apiKey, algorithm, comparator) : getSignFromObject(dataInfo, apiKey, algorithm, comparator);
    }

    public static String getSignFromObject(Object dataInfo, String apiKey, String algorithm) {
        return getSignFromObject(dataInfo, apiKey, algorithm, (Comparator)null);
    }

    public static String getSignFromObject(Object dataInfo, String apiKey, String algorithm, Comparator comparator) {
        ArrayList<String> list = new ArrayList();
        if (null != dataInfo) {
            Class cls = dataInfo.getClass();
            Method[] methodArr = cls.getMethods();
            Method[] var7 = methodArr;
            int var8 = methodArr.length;

            for(int var9 = 0; var9 < var8; ++var9) {
                Method method = var7[var9];
                String methodName = method.getName();

                try {
                    if (methodName.startsWith("get") && !"getClass".equals(methodName) && !StringUtils.isEmpty(method.invoke(dataInfo))) {
                        Object value = method.invoke(dataInfo);
                        boolean pushDataFlag = true;
                        if (value instanceof Collection) {
                            if (((Collection)value).isEmpty()) {
                                pushDataFlag = false;
                            } else {
                                value = JSON.toJSONString(value);
                            }
                        } else if (value instanceof Map) {
                            if (((Map)value).isEmpty()) {
                                pushDataFlag = false;
                            } else {
                                value = JSON.toJSONString(value);
                            }
                        }

                        if (pushDataFlag) {
                            String key = methodName.substring(3);
                            key = key.substring(0, 1).toLowerCase() + key.substring(1);
                            list.add(key + "=" + value + "&");
                        }
                    }
                } catch (Exception var15) {
                    log.error("error:" + method, var15);
                }
            }
        }

        return createSign(list, apiKey, algorithm, comparator);
    }

    public static String getMD5SignFromMap(Map<String, ? extends Object> map, String apiKey) {
        return getSignFromMap(map, apiKey, "MD5");
    }

    public static String getMD5SignFromMap(Map<String, ? extends Object> map, String apiKey, Comparator comparator) {
        return getSignFromMap(map, apiKey, "MD5", comparator);
    }

    public static String getSignFromMap(Map<String, ? extends Object> map, String apiKey, String algorithm) {
        return getSignFromMap(map, apiKey, algorithm, (Comparator)null);
    }

    public static String getSignFromMap(Map<String, ? extends Object> map, String apiKey, String algorithm, Comparator comparator) {
        ArrayList<String> list = new ArrayList();
        if (null != map && !map.isEmpty()) {
            Iterator var5 = map.entrySet().iterator();

            while(true) {
                while(true) {
                    Map.Entry entry;
                    do {
                        do {
                            if (!var5.hasNext()) {
                                return createSign(list, apiKey, algorithm, comparator);
                            }

                            entry = (Map.Entry)var5.next();
                        } while(StringUtils.isEmpty(entry.getValue()));
                    } while("sign".equalsIgnoreCase((String)entry.getKey()));

                    if (entry.getValue() instanceof Collection && !((Collection)entry.getValue()).isEmpty()) {
                        list.add((String)entry.getKey() + "=" + JSON.toJSONString(entry.getValue()) + "&");
                    } else if (entry.getValue() instanceof Map && !((Map)entry.getValue()).isEmpty()) {
                        list.add((String)entry.getKey() + "=" + JSON.toJSONString(entry.getValue()) + "&");
                    } else {
                        list.add((String)entry.getKey() + "=" + entry.getValue() + "&");
                    }
                }
            }
        } else {
            return createSign(list, apiKey, algorithm, comparator);
        }
    }

    private static String createSign(ArrayList<String> list, String apiKey, String algorithm) {
        return createSign(list, apiKey, algorithm, (Comparator)null);
    }

    private static String createSign(ArrayList<String> list, String apiKey, String algorithm, Comparator comparator) {
        String result = null;
        if (null != list && !list.isEmpty()) {
            int size = list.size();
            String[] arrayToSort = (String[])list.toArray(new String[size]);
            if (null == comparator) {
                Arrays.sort(arrayToSort, String.CASE_INSENSITIVE_ORDER);
            } else {
                Arrays.sort(arrayToSort, comparator);
            }

            StringBuilder stringSignTemp = new StringBuilder();

            for(int i = 0; i < size; ++i) {
                stringSignTemp.append(arrayToSort[i]);
            }

            String signTempStr;
            if (!StringUtil.IsNullOrEmpty(apiKey)) {
                stringSignTemp.append("key=" + apiKey);
                signTempStr = stringSignTemp.toString();
            } else {
                signTempStr = stringSignTemp.substring(0, stringSignTemp.length() - 1);
            }

            log.info("createSign Before MD5:" + signTempStr);
            result = encodeToAlgorithm(signTempStr, algorithm).toUpperCase();
        }

        log.info("createSign Result:" + result);
        return result;
    }

    public static String encodeToAlgorithm(String str, String algorithm) {
        if (StringUtil.IsNullOrEmpty(str)) {
            return null;
        } else {
            try {
                MessageDigest messageDigest = MessageDigest.getInstance(algorithm);
                byte[] digest = messageDigest.digest(str.getBytes("utf-8"));
                return new String(Hex.encodeHex(digest));
            } catch (UnsupportedEncodingException | NoSuchAlgorithmException var4) {
                throw unchecked(var4);
            }
        }
    }

    public static RuntimeException unchecked(Exception e) {
        return e instanceof RuntimeException ? (RuntimeException)e : new RuntimeException(e);
    }

    static {
        CASE_INSENSITIVE = String.CASE_INSENSITIVE_ORDER;
        CASE_SENSITIVE = new ComparableComparator();
    }
}
